package pilgun.Multithread.Bank;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;



public class Bank {
	

	private Map<Integer, Account> accounts = new HashMap<Integer, Account>();
	
	public Account maxId(Account a1, Account a2){
		if (a1.getId()<a2.getId()){
			return a2;
		}
		return a1;
	}
	public Account minId(Account a1, Account a2){
		if (a1.getId()<a2.getId()){
			return a1;
		}
		return a2;
	}
	
	public void transfer (Account from, Account to, int amount){
		if (from.equals(to) || to == null || from == null){
			return;
		}
		Lock minLock = minId(from, to).getLock();
		Lock maxLock = maxId(from,to).getLock();
		Condition minCond = minId(from,to).getCondition();
		Condition maxCond = maxId(from,to).getCondition();
		minLock.lock();
		maxLock.lock();
		
		try{
			while (amount > from.getBalance()){
				System.out.println(Thread.currentThread().getName()+" waiting, from: "+from.getId()+" to: "+to.getId()+" balance: "+from.getBalance()+ " amount: "+ amount);
				try {
					maxLock.unlock();
					minCond.await();
					maxLock.lock();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
			
			from.withdraw(amount);
			to.deposit(amount);
			minCond.signalAll();
			maxCond.signalAll();
			System.out.println("running " + Thread.currentThread().getName());
		}
		
		finally{
			maxLock.unlock();
			minLock.unlock();
		}
		
		
	}
	public int sum(){
		int sum = 0;
		for (Account account: accounts.values()){
			sum+=account.getBalance();
		}
		return sum;
	}
	public void addAccount(int id,Account account){
		accounts.put(id, account);
	}
	public Account getAccount(int id){
		return accounts.get(id);
	}
	public int getAccountNum(){
		return accounts.size();
	}
	
	
}